home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 1.iso / dist / fw_exmh.idb / usr / freeware / lib / exmh-2.5 / fileselect.tcl.z / fileselect.tcl
Text File  |  2002-07-08  |  17KB  |  614 lines

  1. #
  2. # fileselect.tcl --
  3. # simple file selector.
  4. #
  5. # Mario Jorge Silva                      msilva@cs.Berkeley.EDU
  6. # University of California Berkeley                 Ph:    +1(510)642-8248
  7. # Computer Science Division, 571 Evans Hall         Fax:   +1(510)642-5775
  8. # Berkeley CA 94720                                 
  9. #
  10. # Copyright 1993 Regents of the University of California
  11. # Permission to use, copy, modify, and distribute this
  12. # software and its documentation for any purpose and without
  13. # fee is hereby granted, provided that this copyright
  14. # notice appears in all copies.  The University of California
  15. # makes no representations about the suitability of this
  16. # software for any purpose.  It is provided "as is" without
  17. # express or implied warranty.
  18. #
  19.  
  20.  
  21. # names starting with "fileselect" are reserved by this module
  22. # no other names used.
  23. # Hack - FSBox is defined instead of fileselect for backwards compatibility
  24.  
  25.  
  26. # this is the proc that creates the file selector box
  27. # purpose - comment string
  28. # defaultName - initial value for name
  29. # cmd - command to eval upon OK
  30. # errorHandler - command to eval upon Cancel
  31. # If neither cmd or errorHandler are specified, the return value
  32. # of the FSBox procedure is the selected file name.
  33.  
  34. # Added preferences support
  35.  
  36. proc fileselect_Init {} {
  37.     global fileselect
  38.     if [info exists fileselect(init)] {
  39.     return
  40.     }
  41.     set fileselect(init) 1
  42.  
  43.     Preferences_Add "FS Box" \
  44. "The file select box lets you scan the directory structure.
  45. The FS box understands '~' and '~user' as shortcuts for your
  46. or the 'user's home directory.  Furthermore it tries to
  47. compelete a partial filename when you press the 'tab'." {
  48.     {fileselect(bigDirHas) fileselectBigDirHas {32} {Suppress startup listing longer than} 
  49. "FS box startup: Do not list a directory that has more than the here
  50. given number of entries.  If the directory has more entries you could
  51. press return to list them or enter a file/directory by hand."}
  52.     {fileselect(dotsByDefault) fileselectDotsByDefault OFF {List .* files by default}
  53. "Determines if dotfiles are listed by default. By default this is
  54. OFF.  The file select box has a checkbutton 'List all' that allows
  55. you to display the dotfiles if you want."}
  56.     {fileselect(home) fileselectHome {} {Default startup directory}
  57. "Defines which directory is listed on startup.  If empty the directory
  58. exmh was started is used."}
  59.     }
  60. }
  61.  
  62. proc FSBox {{purpose "Select file:"} {defaultName ""} {cmd ""} {errorHandler ""}} {
  63.     global fileselect
  64.     global exwin
  65.  
  66.     regsub -all " +" $defaultName _ defaultName
  67.  
  68.     set fileselect(origname) $defaultName
  69.     if $fileselect(dotsByDefault) {
  70.         set fileselect(pattern) "{*,.*}"
  71.        } else {
  72.         set fileselect(pattern) "*"
  73.     }
  74.     if ![info exists fileselect(lastDir)] {
  75.         if {$fileselect(home) == {}} {
  76.             set fileselect(lastDir) [pwd]
  77.         } else {
  78.             set fileselect(lastDir) $fileselect(home)
  79.         }
  80.     }
  81.  
  82.     set w .fileSelect
  83.     if [Exwin_Toplevel $w "Select File" FileSelect] {
  84.     # path independent names for the widgets
  85.     
  86.     set fileselect(list) $w.file.sframe.list
  87.     set fileselect(scroll) $w.file.sframe.scroll
  88.     set fileselect(direntry) $w.file.f1.direntry
  89.     set fileselect(entry) $w.file.f2.entry
  90.  
  91.     set fileselect(ok) $w.but.ok
  92.     set fileselect(cancel) $w.but.quit
  93.     set fileselect(msg) $w.label
  94.     
  95.     set fileselect(result) ""    ;# value to return if no callback procedures
  96.     
  97.     # widgets
  98.     Widget_Label $w label {top fillx pady 10 padx 20} -anchor w -width 24
  99.     Widget_Frame $w file Dialog {left expand fill} -bd 10
  100.     
  101.     Widget_Frame $w.file f1 Exmh {top fillx}
  102.     Widget_Label $w.file.f1 label {left} -text "Dir"
  103.     Widget_Entry $w.file.f1 direntry {right fillx expand}  -width 30
  104.     
  105.     Widget_Frame $w.file sframe
  106.     
  107.     scrollbar $w.file.sframe.yscroll -relief sunken \
  108.         -command [list $w.file.sframe.list yview]
  109.     FontWidget listbox $w.file.sframe.list -relief sunken \
  110.         -yscroll [list $w.file.sframe.yscroll set] -setgrid 1
  111.         if {$exwin(scrollbarSide) == "left"} {
  112.         pack append $w.file.sframe \
  113.             $w.file.sframe.yscroll {left filly} \
  114.             $w.file.sframe.list {right expand fill} 
  115.         } else {
  116.         pack append $w.file.sframe \
  117.             $w.file.sframe.yscroll {right filly} \
  118.             $w.file.sframe.list {left expand fill} 
  119.     }
  120.     Widget_Frame $w.file f2 Exmh {top fillx}
  121.     Widget_Label $w.file.f2 label {left} -text Name
  122.     Widget_Entry $w.file.f2 entry {right fillx expand}
  123.     
  124.     # buttons
  125.     $w.but.quit configure -text Cancel \
  126.         -command [list fileselect.cancel.cmd $w]
  127.     
  128.     Widget_AddBut $w.but ok OK \
  129.         [list fileselect.ok.cmd $w $cmd $errorHandler] {left padx 1 fill}
  130.     
  131.     Widget_AddBut $w.but list List \
  132.         [list fileselect.list.cmd $w] {left padx 1 fill}
  133.     Widget_CheckBut $w.but listall "List all" fileselect(pattern)
  134.     $w.but.listall configure -onvalue "{*,.*}" -offvalue "*" \
  135.         -command {fileselect.list.cmd $fileselect(direntry)}
  136.     $w.but.listall deselect
  137.     
  138.     # Set up bindings for the browser.
  139.     Widget_BindEntryCmd $fileselect(entry) <Return> \
  140.         "$fileselect(ok) invoke"
  141.     Widget_BindEntryCmd $fileselect(entry) <Control-c> \
  142.         "$fileselect(cancel) invoke"
  143.     Widget_BindEntryCmd $fileselect(direntry) <Return> \
  144.         "fileselect.list.cmd %W"
  145.     Widget_BindEntryCmd $fileselect(direntry) <space> \
  146.         "fileselect.tab.dircmd"
  147.     Widget_BindEntryCmd $fileselect(entry) <space> \
  148.         "fileselect.tab.filecmd"
  149.     Widget_BindEntryCmd $fileselect(direntry) <Tab> \
  150.         "fileselect.tab.dircmd"
  151.     Widget_BindEntryCmd $fileselect(entry) <Tab> \
  152.         "fileselect.tab.filecmd"
  153.     $fileselect(list) config -selectmode browse
  154.     
  155.     bind $fileselect(list) <Button-1> {
  156.         # puts stderr "button 1 release"
  157.         %W select set [%W nearest %y]
  158.         $fileselect(entry) delete 0 end
  159.         $fileselect(entry) insert 0 [%W get [%W nearest %y]]
  160.     }
  161.     
  162.     bind $fileselect(list) <Key> {
  163.         %W select set [%W nearest %y]
  164.         $fileselect(entry) delete 0 end
  165.         $fileselect(entry) insert 0 [%W get [%W nearest %y]]
  166.     }
  167.     
  168.     bind $fileselect(list) <Double-ButtonPress-1> {
  169.         # puts stderr "double button 1"
  170.         %W select set [%W nearest %y]
  171.         $fileselect(entry) delete 0 end
  172.         $fileselect(entry) insert 0 [%W get [%W nearest %y]]
  173.         $fileselect(ok) invoke
  174.     }
  175.     
  176.     bind $fileselect(list) <Return> {
  177.         %W select set [%W nearest %y]
  178.         $fileselect(entry) delete 0 end
  179.         $fileselect(entry) insert 0 [%W get [%W nearest %y]]
  180.         $fileselect(ok) invoke
  181.     }
  182.     }
  183.     set fileselect(text) $purpose
  184.     $fileselect(msg) configure -text $purpose
  185.     $fileselect(entry) delete 0 end
  186.     $fileselect(entry) insert 0 [file tail $defaultName]
  187.  
  188.     set dir [file dirname $defaultName]
  189.     if {"$dir" == "." && [info exists fileselect(lastDir)]} {
  190.         set dir $fileselect(lastDir)
  191.     }
  192.     if [catch {pwd} fileselect(pwd)] {
  193.         cd
  194.         set fileselect(pwd) [pwd]
  195.     }
  196.     fileselect.cd $dir
  197.     $fileselect(direntry) delete 0 end
  198.     $fileselect(direntry) insert 0 $dir/
  199.  
  200.     $fileselect(list) delete 0 end
  201.     $fileselect(list) insert 0 "Big directory:"
  202.     $fileselect(list) insert 1 $dir
  203.     $fileselect(list) insert 2 "Press Return for Listing"
  204.  
  205.     fileselect.list.cmd $fileselect(direntry) startup
  206.  
  207.     # set kbd focus to entry widget
  208.  
  209.     focus $fileselect(entry)
  210.  
  211.     # Wait for button hits if no callbacks are defined
  212.  
  213.     if {"$cmd" == "" && "$errorHandler" == ""} {
  214.         # wait for the box to be destroyed
  215.         tkwait variable fileselect(result)
  216.  
  217.         set path $fileselect(result)
  218.         set dir [file dirname $fileselect(result)]
  219.         if {$dir == "."} {
  220.             set dir [pwd]
  221.         }
  222.         set fileselect(lastDir) $dir
  223.         fileselect.cd $fileselect(pwd)
  224.         return [string trimright [string trim $path] /]
  225.     }
  226.     fileselect.cd $fileselect(pwd)
  227.     return ""
  228. }
  229.  
  230. proc fileselect.cd { dir } {
  231.     global fileselect
  232.     if [catch {cd $dir} err] {
  233.         fileselect.yck $dir
  234.         cd
  235.     }
  236. }
  237. # auxiliary button procedures
  238.  
  239. proc fileselect.yck { {tag {}} } {
  240.     global fileselect
  241.     $fileselect(msg) configure -text "Yck! $tag"
  242. }
  243. proc fileselect.ok {} {
  244.     global fileselect
  245.     $fileselect(msg) configure -text $fileselect(text)
  246. }
  247.  
  248. proc fileselect.cancel.cmd {w} {
  249.     global fileselect
  250.     set fileselect(result) {}
  251.     Exwin_Dismiss $w
  252. }
  253.  
  254. proc fileselect.list.cmd {w {state normal}} {
  255.     global fileselect
  256.     set seldir [$fileselect(direntry) get]
  257.     if {[catch {glob $seldir} dir]} {
  258.         fileselect.yck "glob failed"
  259.         return
  260.     }
  261.     if {[llength $dir] > 1} {
  262.         set dir [file dirname $seldir]
  263.         set pat [file tail $seldir]
  264.     } else {
  265.         set pat $fileselect(pattern)
  266.         set dir [lindex $dir 0]
  267.     }
  268.     fileselect.ok
  269.     update idletasks
  270.     if [file isdirectory $dir] {
  271.         fileselect.getfiles $dir $pat $state
  272.         focus $fileselect(entry)
  273.     } else {
  274.         fileselect.yck "not a dir"
  275.     }
  276. }
  277.  
  278. proc fileselect.ok.cmd {w cmd errorHandler} {
  279.     global fileselect
  280.     set selname [$fileselect(entry) get]
  281.     set seldir [$fileselect(direntry) get]
  282.  
  283.     if [string match /* $selname] {
  284.         set selected $selname
  285.     } else {
  286.         if [string match ~* $selname] {
  287.             set selected $selname
  288.         } else {
  289.             set selected [string trimright $seldir /]/$selname
  290.         }
  291.     }
  292.  
  293.     # some nasty file names may cause "file isdirectory" to return an error
  294.     if [catch {file isdirectory $selected} isdir] {
  295.         fileselect.yck "isdirectory failed"
  296.         return
  297.     }
  298.     if [catch {glob $selected} globlist] {
  299.         if ![file isdirectory [file dirname $selected]] {
  300.             fileselect.yck "bad pathname"
  301.             return
  302.         }
  303.         set globlist [list $selected]
  304.     }
  305.     fileselect.ok
  306.     update idletasks
  307.  
  308.     if {[llength $globlist] > 1} {
  309.         set dir [file dirname $selected]
  310.         set pat [file tail $selected]
  311.         fileselect.getfiles $dir $pat
  312.         return
  313.     } else {
  314.         set selected [lindex $globlist 0]
  315.     }
  316.     if [file isdirectory $selected] {
  317.         fileselect.getfiles $selected $fileselect(pattern)
  318.         $fileselect(entry) delete 0 end
  319.         $fileselect(entry) insert 0 $fileselect(origname)
  320.         return
  321.     }
  322.  
  323.     if {$cmd != {}} {
  324.         $cmd $selected
  325.     } else {
  326.         set fileselect(result) $selected
  327.     }
  328.     Exwin_Dismiss $w
  329. }
  330.  
  331. proc fileselect.getfiles { dir {pat *} {state normal} } {
  332.     global fileselect
  333.     $fileselect(msg) configure -text Listing...
  334.     update idletasks
  335.  
  336.     fileselect.cd $dir
  337.     if [catch {set files [lsort [glob -nocomplain $pat]]} err] {
  338.         $fileselect(msg) configure -text $err
  339.         $fileselect(list) delete 0 end
  340.         update idletasks
  341.         return
  342.     }
  343.     switch -- $state {
  344.     normal {
  345.         # Normal case - show current directory
  346.         $fileselect(direntry) delete 0 end
  347.         $fileselect(direntry) insert 0 [pwd]/
  348.     }
  349.     opt {
  350.         # Directory already OK (tab related)
  351.     }
  352.     newdir {
  353.         # Changing directory (tab related)
  354.         fileselect.cd $fileselect(lastDir)
  355.     }
  356.     startup {
  357.         # Avoid listing huge directories upon startup.
  358.         $fileselect(direntry) delete 0 end
  359.         $fileselect(direntry) insert 0 [pwd]/
  360.         if {[llength $files] > $fileselect(bigDirHas)} {
  361.         fileselect.ok
  362.         return
  363.         }
  364.     }
  365.     }
  366.  
  367.     # build a reordered list of the files: directories are displayed first
  368.     # and marked with a trailing "/"
  369.     if [string compare $dir /] {
  370.         fileselect.putfiles $files [expr {($pat == "*") ? 1 : 0}]
  371.     } else {
  372.         fileselect.putfiles $files
  373.     }
  374.     fileselect.ok
  375. }
  376.  
  377. proc fileselect.putfiles {files {dotdot 0} } {
  378.     global fileselect
  379.  
  380.     $fileselect(list) delete 0 end
  381.     if {$dotdot} {
  382.         $fileselect(list) insert end "../"
  383.         set dirnum 1
  384.     } else {
  385.         set dirnum 0
  386.     }
  387.     foreach i $files {
  388.     catch {
  389.         if {[file isdirectory $i]} {
  390.             if {"x$i" == "x."} continue
  391.             $fileselect(list) insert $dirnum $i/
  392.             incr dirnum
  393.         } else {
  394.             $fileselect(list) insert end $i
  395.         }
  396.     }
  397.     }
  398. }
  399.  
  400. proc FileExistsDialog { name } {
  401.     set w .fileExists
  402.     global fileExists
  403.     set fileExists(ok) 0
  404.     if [Exwin_Toplevel $w "File Exists"] {
  405.     message $w.msg -aspect 1000
  406.     pack $w.msg -side top -fill both -padx 20 -pady 20
  407.     $w.but.quit config -text Cancel -command {FileExistsCancel}
  408.     button $w.but.ok -text OK -command {FileExistsOK}
  409.     pack $w.but.ok -side left
  410.     bind $w.msg <Return> {FileExistsOK}
  411.     }
  412.     $w.msg config -text "Warning: file exists
  413. $name
  414. OK to overwrite it?"
  415.  
  416.     set fileExists(focus) [focus]
  417.     focus $w.msg
  418.     grab $w
  419.     tkwait variable fileExists(ok)
  420.     grab release $w
  421.     Exwin_Dismiss $w
  422.     return $fileExists(ok)
  423. }
  424. proc FileExistsCancel {} {
  425.     global fileExists
  426.     set fileExists(ok) 0
  427. }
  428. proc FileExistsOK {} {
  429.     global fileExists
  430.     set fileExists(ok) 1
  431. }
  432.  
  433. proc fileselect.getfiledir { dir {basedir [pwd]} } {
  434.     global fileselect
  435.  
  436.     set path [$fileselect(direntry) get]
  437.     set returnList {}
  438.  
  439.     if {$dir != 0} {
  440.     if {[string index $path 0] == "~"} {
  441.         set path $path/
  442.     }
  443.     } else {
  444.     set path [$fileselect(entry) get]
  445.     }
  446.     if [catch {set listFile [glob -nocomplain $path*]}] {
  447.     return  $returnList
  448.     }
  449.     set newdir "."
  450.     foreach el $listFile {
  451.     if {$dir != 0} {
  452.         if [file isdirectory $el] {
  453.         lappend returnList [file tail $el]
  454.         }
  455.     } elseif ![file isdirectory $el] {
  456.         lappend returnList [file tail $el]
  457.         set newdir [file dirname $el]
  458.     }        
  459.     }
  460.     if {[string compare $newdir "."] != 0} {
  461.     $fileselect(direntry) delete 0 end
  462.     $fileselect(direntry) insert 0 $newdir
  463.     }
  464.     
  465.     return $returnList
  466. }
  467.  
  468. proc fileselect.gethead { list } {
  469.     set returnHead ""
  470.  
  471.     for {set i 0} {[string length [lindex $list 0]] > $i}\
  472.     {incr i; set returnHead $returnHead$thisChar} {
  473.         set thisChar [string index [lindex $list 0] $i]
  474.         foreach el $list {
  475.         if {[string length $el] < $i} {
  476.             return $returnHead
  477.         }
  478.         if {$thisChar != [string index $el $i]} {
  479.             return $returnHead
  480.         }
  481.         }
  482.     }
  483.     return $returnHead
  484. }
  485.     
  486. proc fileselect.expand.tilde { } {
  487.     global fileselect
  488.  
  489.     set entry [$fileselect(direntry) get]
  490.     set dir [string range $entry 1 [string length $entry]]
  491.  
  492.     if {$dir == ""} {
  493.     return
  494.     }
  495.  
  496.     set listmatch {}
  497.  
  498.     ## look in /etc/passwd
  499.     if [file exists /etc/passwd] {
  500.     if [catch {set users [exec cat /etc/passwd | sed s/:.*//]} err] {
  501.         puts "Error\#1 $err"
  502.         return
  503.     }
  504.     set list [split $users "\n"]
  505.     }
  506.     if {[lsearch -exact $list "+"] != -1} {
  507.     if [catch {set users [exec ypcat passwd | sed s/:.*//]} err] {
  508.         puts "Error\#2 $err"
  509.         return
  510.     }
  511.     set list [concat $list [split $users "\n"]]
  512.     }
  513.     $fileselect(list) delete 0 end
  514.     foreach el $list {
  515.     if [string match $dir* $el] {
  516.         lappend listmatch $el
  517.         $fileselect(list) insert end $el
  518.     }
  519.     }
  520.     set addings [fileselect.gethead $listmatch]
  521.     if {$addings == ""} {
  522.     return
  523.     }
  524.     $fileselect(direntry) delete 0 end
  525.     if {[llength $listmatch] == 1} {
  526.     $fileselect(direntry) insert 0 [file dirname ~$addings/]
  527.     fileselect.getfiles [$fileselect(direntry) get]
  528.     } else {
  529.     $fileselect(direntry) insert 0 ~$addings
  530.     }
  531. }
  532.  
  533. proc fileselect.tab.dircmd { } {
  534.     global fileselect
  535.  
  536.     set dir [$fileselect(direntry) get]
  537.     if {$dir == ""} {
  538.     $fileselect(direntry) delete 0 end
  539.         $fileselect(direntry) insert 0 [pwd]
  540.     if [string compare [pwd] "/"] {
  541.         $fileselect(direntry) insert end /
  542.     }
  543.     return
  544.     }
  545.  
  546.     if [catch {set tmp [file isdirectory [file dirname $dir]]}] {
  547.     if {[string index $dir 0] == "~"} {
  548.         fileselect.expand.tilde
  549.     }
  550.     return
  551.     }
  552.     if {!$tmp} {
  553.     return
  554.     }
  555.     set dirFile [fileselect.getfiledir 1 $dir]
  556.     if ![llength $dirFile] {
  557.     return
  558.     }
  559.     if {[llength $dirFile] == 1} {
  560.     $fileselect(direntry) delete 0 end
  561.     $fileselect(direntry) insert 0 [file dirname $dir]
  562.     if [string compare [file dirname $dir] /] {
  563.         $fileselect(direntry) insert end /[lindex $dirFile 0]/
  564.     } else {
  565.         $fileselect(direntry) insert end [lindex $dirFile 0]/
  566.     }
  567.     fileselect.getfiles [$fileselect(direntry) get] \
  568.         "[file tail [$fileselect(direntry) get]]$fileselect(pattern)" opt
  569.     return
  570.     }
  571.     set headFile [fileselect.gethead $dirFile]
  572.     $fileselect(direntry) delete 0 end
  573.     $fileselect(direntry) insert 0 [file dirname $dir]
  574.     if [string compare [file dirname $dir] /] {
  575.     $fileselect(direntry) insert end /$headFile
  576.     } else {
  577.     $fileselect(direntry) insert end $headFile
  578.     }
  579.     if {$headFile == "" && [file isdirectory $dir]} {
  580.     fileselect.getfiles $dir\
  581.         "[file tail [$fileselect(direntry) get]]$fileselect(pattern)" opt
  582.     } else {
  583.     fileselect.getfiles [file dirname $dir]\
  584.         "[file tail [$fileselect(direntry) get]]*" newdir
  585.     }
  586. }
  587.  
  588. proc fileselect.tab.filecmd { } {
  589.     global fileselect
  590.  
  591.     set dir [$fileselect(direntry) get]
  592.     if {$dir == ""} {
  593.     set dir [pwd]
  594.     }
  595.     if {![file isdirectory $dir]} {
  596.     error "dir $dir doesn't exist"
  597.     }
  598.     set listFile [fileselect.getfiledir 0 $dir]
  599. #    puts $listFile
  600.     if ![llength $listFile] {
  601.     return
  602.     }
  603.     if {[llength $listFile] == 1} {
  604.     $fileselect(entry) delete 0 end
  605.     $fileselect(entry) insert 0 [lindex $listFile 0]
  606.     return
  607.     }
  608.     set headFile [fileselect.gethead $listFile]
  609.     $fileselect(entry) delete 0 end
  610.     $fileselect(entry) insert 0 $headFile
  611.     fileselect.getfiles $dir "[$fileselect(entry) get]$fileselect(pattern)" opt
  612. }
  613.